#include <iostream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"

//存放html网页的路径
const std::string src_path = "data/input";
//处理后内容存放位置
const std::string output = "data/raw_html/raw.txt";

typedef struct DocInfo
{
    std::string title;//文档的标题
    std::string content;//文档内容
    std::string url;//该文档在官网中的url
}DocInfo_t;


bool EnumFile(const std::string& src_path,std::vector<std::string>* files_list);
bool ParseHtml(const std::vector<std::string>& files_list,std::vector<DocInfo_t>* results);
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output);

int main()
{
    std::vector<std::string> file_list;
    //1. 递归式的把html文件名和路径，全部保存到files_list中，方便后续一一读取
    if(!EnumFile(src_path,&file_list))
    {
        std::cerr<<"enum file name error!"<<std::endl;
        return 1;
    }
    //2. 根据file_list读取每个文件的内容并解析
    std::vector<DocInfo_t> results;
    if(!ParseHtml(file_list,&results))
    {
        std::cerr<<"parse html error"<<std::endl;
        return 2;
    }
    //3. 将解析完的内容，写入到output中，以\3为每个文档的分割符
    if(!SaveHtml(results,output))
    {
        std::cerr<<"save html error"<<std::endl;
        return 3;
    }
    return 0;
}

bool EnumFile(const std::string& src_path,std::vector<std::string>* files_list)
{
    namespace fs = boost::filesystem;
    fs::path root_path(src_path);

    //判断路径是否存在
    if(!fs::exists(root_path))
    {
        std::cerr<<src_path<<" not exists!"<<std::endl;
        return false;
    }
    //定义空迭代器判断递归是否结束
    fs::recursive_directory_iterator end;
    for(fs::recursive_directory_iterator it(root_path);it!=end;++it)
    {
        //筛除非普通文件
        if(!fs::is_regular_file(*it))
            continue;
        //筛除非html文件
        if(it->path().extension() != ".html")
            continue;
        //将合法路径添加到files_list中
        //std::cout<<"debug: "<<it->path().string()<<std::endl;
        files_list->push_back(it->path().string());
    }
    return true;
}
//提取标题
static bool ParseTitle(const std::string& file,std::string *title)
{
    size_t begin = file.find("<title>");
    if(begin == std::string::npos)
        return false;
    size_t end = file.find("</title>");
    if(end == std::string::npos)
        return false;
    begin += std::string("<title>").size();
    if(begin > end)
        return false;
    *title = file.substr(begin,end-begin);
    return true;
}
//提取内容
static bool ParseContent(const std::string& file,std::string* content)
{
    //简易状态机处理标签
    enum status{
        LABLE,
        CONTENT
    };
    enum status s = LABLE;
    for(auto c : file)
    {
        switch (s)
        {
        case LABLE:
            if(c == '>') s = CONTENT;
            break;
        case CONTENT:
            if(c == '<') s = LABLE;
            else 
            {
                //文本中的'\n'修改成' '
                if(c == '\n') c = ' ';
                content->push_back(c);
            }
            break;
        default:
            break;
        }
    }
    return true;
}
//提取url地址
static bool ParseUrl(const std::string& file_path,std::string* url)
{
    std::string url_head = "https://www.boost.org/doc/libs/1_88_0/doc/html";
    std::string url_tail = file_path.substr(src_path.size());
    *url = url_head + url_tail;
    return true;
}
//debug
void ShowDoc(const DocInfo_t& doc)
{
    std::cout<<"tile: "<<doc.title<<std::endl;
    std::cout<<"content: "<<doc.content<<std::endl;
    std::cout<<"url: "<<doc.url<<std::endl;
}

bool ParseHtml(const std::vector<std::string>& files_list,std::vector<DocInfo_t>* results)
{
    for(const std::string& file : files_list)
    {
        std::string result;
        if(!ns_util::FileUtil::ReadFile(file,&result))
            continue;

        DocInfo_t doc;
        if(!ParseTitle(result,&doc.title))
            continue;

        if(!ParseContent(result,&doc.content))
            continue;
  
        if(!ParseUrl(file,&doc.url))
            continue;

        //解析完毕
        //ShowDoc(doc);
        results->push_back(std::move(doc));
    }
    return true;
}
bool SaveHtml(const std::vector<DocInfo_t>& results,const std::string& output)
{
    const char SEP = '\3';
    std::ofstream out(output,std::ios::out | std::ios::binary);
    if(!out.is_open())
    {
        std::cerr<<"open "<<output<<" error!"<<std::endl;
        return false;
    }
    // title\3conten\3url\n title\3conten\3url\n title\3conten\3url\n
    for(auto doc : results)
    {
        std::string doc_string;
        doc_string = doc.title;
        doc_string += SEP;
        doc_string += doc.content;
        doc_string += SEP;
        doc_string += doc.url;
        doc_string += '\n';
        out.write(doc_string.c_str(),doc_string.size());
    }
    out.close();
    return true;
}
